/**
 * @author : andy
 * @description : 树操作
 */
type TreeConfigOptions = {
  /** 树遍历的子树的key值，默认为children，有可能是其他值 */
  childProps: string;
}
/**
 * 遍历树，并返回所有节点中指定的值的数组
 * @param tree 树数据
 * @param getValue 获取树节点值的函数
 * @param options 作为子节点数组的可选属性名称
 * @returns 所有节点中指定的值的数组
 */
export function traverseTreeValues<T , V> (tree: T[] , getValue: (node: T) => V , options: TreeConfigOptions = {childProps : 'children'}): V[] {
  const result: V[] = [];
  const childProps = options.childProps;
  const traverse = (treeNode: T) => {
    const value = getValue(treeNode);
    result.push(value);
    const children = treeNode[childProps as keyof T] as T[];
    if (!children) {
      return;
    }
    if (children.length > 0) {
      for (const child of children) {
        traverse(child);
      }
    }
  }
  for (const node of tree) {
    traverse(node);
  }
  return result.filter(item => !!item);
}
/**
 * 根据过滤条件，返回原数组数据结构的树数据
 * @param tree 树数据
 * @param filter 过滤函数
 * @param options 作为子节点数组的可选属性名称
 * @returns 过滤后的树数据（保存原来的结构）
 */
export function filterTree<T> (tree: T[] , filter: (node: T) => boolean , options: TreeConfigOptions = {childProps : 'children'}): T[] {
  const childProps = options.childProps;
  const _filterTree = (tree: T[]) => {
    return tree.filter((node: T) => {
      if (filter(node)) {
        if (node[childProps as keyof T]) {
          (node as Record<string , unknown>)[childProps] = _filterTree(node[childProps as keyof T] as T[]);
        }
        return true;
      }
      return false;
    })
  }
  return _filterTree(tree);
}
/**
 * 遍历树结构，给每一个树节点添加相应的属性
 * @param tree 树数据
 * @param add 需要给树结构添加的数据的方法
 * @param options 作为子节点数组的可选属性名称
 * @returns 返回添加数据后的树数据
 */
export function traverseTreeToAddProps<T , K extends T> (tree: T[] , add: (node: K) => void , options: TreeConfigOptions = {childProps : 'children'}): T[] {
  const childProps = options.childProps;
  const _traverse = (tree: T[]) => {
    return tree.map(node => {
      add(node as K);
      if (node[childProps as keyof T]) {
        (node as Record<string , unknown>)[childProps] = _traverse(node[childProps as keyof T] as T[]);
      }
      return node;
    })
  }
  return _traverse(tree);
}
/**
 * 通过给定的一个值，找到树结构对应的节点
 * @param tree 树数据
 * @param propName 树节点的属性key名称
 * @param value 给定的一个值，找到树节点中与这个值相等的节点
 * @param ooptions 指定树节点的哪个属性
 */
export function findTreeNodeByValue<T , K extends keyof T> (tree: T[] , propName: K , value: unknown , options: TreeConfigOptions = {childProps : 'children'}): T | null {
  let treeNode: T | null = null;
  const childProps = options.childProps;
  const _traverse = (tree: T[]) => {
    tree.map(node => {
      const propValue = node[propName];
      if (propValue && propValue === value) {
        treeNode = node;
      }
      const children = node[childProps as keyof T] as T[];
      if (children) {
        _traverse(children);
      }
    })
  }
  _traverse(tree);
  return treeNode;
}
/**
 * 获取树节点路径
 * @param curKey 树节点标识的值
 * @param data 树
 * @param options 可选的属性，有时候遍历树的时候，不一定是key，有可能是id或者其他
 */
export function getPathByKey<T extends Record<string , unknown>> (curKey: string , data: T[] , options: {keyProp: string} = {keyProp : 'key'}) {
  let result: T[] = [];
  const traverse = (curKey: string , path: T[], data: T[]) => {
    if (data.length === 0) {
      return;
    };
    for (const item of data) {
      const key = item[options.keyProp as keyof typeof item];
      path.push(item);
      if (key === curKey) {
        result = JSON.parse(JSON.stringify(path));
        return result;
      }
      const children = Array.isArray(item.children) ? item.children : [];
      traverse(curKey , path , children);
      path.pop();
    }
  }
  traverse(curKey , [] , data);
  return result;
};